# Purpose: Executes agent steps by calling MCP Tools via MCP Client.
# Changes:
# - Removed specific RPCError import/check. Relies on broader exception handling.
# - Changed session.call_tool argument from 'tool_name=' to 'name='.
# - Ensured get_logger(__name__) is used.

import logging
from typing import Any, Dict

# Use relative imports
from ..mcp_client import get_mcp_session
from ..core.exceptions import AgentError, MCPClientError, AgentExecutionError
from .agent_types import Step

# Import MCP types if needed for other purposes, but not RPCError specifically
try:
    from mcp import types as mcp_types
except ImportError:
    logging.warning("Could not import 'types' from 'mcp' package.")
    mcp_types = None

# Use core logger setup
from ..core.logging_setup import get_logger
logger = get_logger(__name__)


class Executor:
    """Handles the execution of a single plan step by calling the corresponding MCP Tool."""

    async def execute_step(self, step: Step) -> Any:
        """Executes a single step by calling the MCP tool via the MCP client."""
        # Use 'name' based on Pyright error for the tool identifier parameter
        tool_identifier_name = step.tool_name
        arguments = step.arguments
        logger.info(f"Executor: Executing Step {step.id}: Tool='{tool_identifier_name}'")
        logger.debug(f"Executor: Arguments for '{tool_identifier_name}': {arguments}")

        try:
            session = await get_mcp_session()

            # --- Call MCP Tool ---
            # *** Changed keyword argument from 'tool_name' to 'name' ***
            logger.debug(f"Executor: Calling session.call_tool(name='{tool_identifier_name}')...")
            result = await session.call_tool(name=tool_identifier_name, arguments=arguments)

            log_result = result
            res_type = type(result).__name__
            if isinstance(result, bytes): log_result = f"<bytes len={len(result)}>"
            elif isinstance(result, (str, list, dict)) and len(str(result)) > 200:
                 log_result = repr(result)[:200] + "..."
            logger.info(f"Executor: Tool '{tool_identifier_name}' executed successfully. Result Type: {res_type}")
            logger.debug(f"Executor: Result for '{tool_identifier_name}': {log_result}")

            return result

        except MCPClientError as e:
             # Error related to MCP communication itself
             logger.error(f"Executor: MCP Client error executing tool '{tool_identifier_name}': {e}", exc_info=False)
             raise AgentExecutionError(
                 message=f"MCP Client communication failed for step {step.id} ('{tool_identifier_name}'): {e}",
                 step_id=step.id,
                 tool_name=tool_identifier_name
             ) from e

        except Exception as e:
            # Catch other exceptions that might occur during the call
            # This could include errors raised by the server-side tool implementation
            # or errors from the MCP protocol layer if not caught as MCPClientError.
            logger.error(f"Executor: Unexpected error executing tool '{tool_identifier_name}': {type(e).__name__} - {e}", exc_info=True)
            error_msg = f"Error executing tool '{tool_identifier_name}': {type(e).__name__} - {e}"

            # Raise AgentExecutionError with context
            raise AgentExecutionError(
                message=error_msg,
                step_id=step.id,
                tool_name=tool_identifier_name
            ) from e